1 module unde.games.dizzy.omega.bird; 2 3 import derelict.opengl3.gl; 4 5 import std.algorithm; 6 import std.conv; 7 import std.math; 8 import std.stdio; 9 import unde.games.dizzy.omega.dizzy; 10 import unde.games.dizzy.omega.main; 11 import unde.games.object; 12 import unde.games.renderer; 13 import unde.games.collision_detector; 14 import unde.games.object; 15 import unde.global_state; 16 17 class Bird:StaticGameObject 18 { 19 static int num; 20 int number; 21 22 int hidden; 23 24 enum SPEED = 0.1; 25 enum G = 0.02; 26 enum MAX_V = 0.3; 27 enum A = 0.01; 28 29 float def_x, def_y, def_z; 30 float dx = 0.0, dy = 0.0; 31 float rx; 32 33 int fly; 34 35 float[7][3] flame_coords; 36 37 Dizzy the_hero; 38 39 bool search_surface; 40 static GLuint rope_texture; 41 ulong delay; 42 43 this(MainGameObject root, float[3] coords, float rx, Dizzy hero, ulong delay = 0) 44 { 45 def_x = x = coords[0]; 46 def_y = y = coords[1]; 47 def_z = z = coords[2]; 48 this.rx = rx; 49 this.delay = delay; 50 the_hero = hero; 51 number = num++; 52 models["bird"] = root.models["bird"]; 53 models["flame"] = root.models["flame"]; 54 dx = SPEED; 55 56 collision_objects["solid"] = root.collision_objects["solid"]; 57 super(root); 58 } 59 60 void start_fly() 61 { 62 fly = 1; 63 } 64 65 void fall() 66 { 67 fly = 2; 68 } 69 70 bool fly_anim(GlobalState gs, string name) 71 { 72 float f = (frame*4)%240; 73 float degree = 0.0; 74 float translate = 0.0; 75 76 if (f < 120.0) 77 translate = 0.2 - 0.4*f/120.0; 78 else if (f < 240.0) 79 translate = -0.2 + 0.4*(f - 120.0)/120.0; 80 81 if (f < 120.0) 82 degree = f/2 - 30.0; 83 else if (f < 240.0) 84 degree = 30.0 - (f/2 - 60.0); 85 86 glTranslatef(0.0, translate, 0.0); 87 88 if (name == "BirdLeftWing") 89 { 90 glRotatef(degree, -1.0, 0.0, 0.0); 91 } 92 93 if (name == "BirdRightWing") 94 { 95 glRotatef(-degree, -1.0, 0.0, 0.0); 96 } 97 98 return true; 99 } 100 101 void hide() 102 { 103 hidden++; 104 } 105 106 override void draw(GlobalState gs) 107 { 108 if ( abs(root.scrx-x) > 32.0 && 109 abs(root.scry-y) > 18.0 ) 110 return; 111 112 if (!hidden) 113 { 114 glPushMatrix(); 115 glTranslatef(x, y, z); 116 glRotatef(atan2(dy, dx)*180/PI,0,1,0); 117 recursive_render(gs, models["bird"], &fly_anim); 118 glPopMatrix(); 119 120 foreach(flame; flame_coords) 121 { 122 if (!flame[0].isNaN()) 123 { 124 glPushMatrix(); 125 glTranslatef(flame[0], flame[1], flame[2]); 126 glScalef(flame[3], flame[3], flame[3]); 127 recursive_render(gs, models["flame"]); 128 glPopMatrix(); 129 } 130 } 131 } 132 } 133 134 override bool tick(GlobalState gs) 135 { 136 if ( hidden || abs(root.scrx-x) > 32.0 && 137 abs(root.scry-y) > 18.0 ) 138 return true; 139 140 frame++; 141 142 if (frame < delay) return true; 143 144 x += dx; 145 y += dy; 146 147 if (the_hero is null) return true; 148 149 foreach (ref flame; flame_coords) 150 { 151 if (!flame[0].isNaN()) 152 { 153 flame[0..3] += flame[4..7]; 154 flame[3] += 0.02; 155 156 if (abs(the_hero.x - flame[0]) < 1.5 && 157 flame[1] > the_hero.y && 158 flame[1] < the_hero.y+2.5) 159 { 160 the_hero.energy -= 1; 161 if (the_hero.energy <= 0.0) 162 { 163 the_hero.die("Flame"); 164 } 165 } 166 } 167 } 168 169 if (!flame_coords[0][0].isNaN() && 170 flame_coords[0][3] > 1.0) 171 { 172 flame_coords[2] = flame_coords[1]; 173 flame_coords[1] = flame_coords[0]; 174 flame_coords[0] = flame_coords[0].init; 175 } 176 else if (!flame_coords[1][0].isNaN() && 177 flame_coords[1][3] > 1.5) 178 { 179 flame_coords[2] = flame_coords[1]; 180 flame_coords[1] = flame_coords[1].init; 181 } 182 else if (!flame_coords[2][0].isNaN() && 183 flame_coords[2][3] > 2.0) 184 { 185 flame_coords[2] = flame_coords[2].init; 186 } 187 188 if ((dx > 0 && the_hero.x > (x+3.0) && 189 the_hero.x - (x+3.0) < 7.0 || 190 dx < 0 && the_hero.x < (x-3.0) && 191 (x-3.0) - the_hero.x < 7.0) && 192 abs(the_hero.y - y) < 3.0 ) 193 { 194 if (flame_coords[0][0].isNaN()) 195 { 196 flame_coords[0] = [x + dx*36, y, z, 197 0.5, 2*dx, 2*dy, 0]; 198 } 199 } 200 201 if (fly == 1) 202 { 203 dx = the_hero.x - x; 204 dy = the_hero.y+2.0 - y; 205 float l = sqrt(dx^^2 + dy^^2); 206 float s = SPEED * (l/20.0); 207 if (s > 2.0*SPEED) s = 2.0*SPEED; 208 if (s < 0.5*SPEED) s = 0.5*SPEED; 209 l /= s; 210 dx /= l; 211 dy /= l; 212 z = -5.0; 213 } 214 else if (fly == 2) 215 { 216 dy -= G; 217 if (dy < -MAX_V) dy = -MAX_V; 218 219 float x0 = x-0.5; 220 float x1 = x+0.5; 221 float y0 = y-0.5; 222 float y1 = y+0.5; 223 float z0 = z-8.0; 224 float z1 = z+8.0; 225 226 auto mb = if_intersect (collision_objects["solid"], [x0, y0, z0, x1, y1, z1]); 227 if (mb > 0 || y < -6.0) 228 { 229 DizzyOmega dz = cast(DizzyOmega) root; 230 dz.bird_item.x = x; 231 dz.bird_item.y = y; 232 dz.bird_item.z = 0; 233 dz.track = 1; 234 dz.play_music(); 235 hide(); 236 } 237 } 238 else 239 { 240 if (x > rx) 241 dx = -SPEED; 242 if (x < def_x) 243 dx = SPEED; 244 } 245 246 return true; 247 } 248 249 override void load(string[string] s) 250 { 251 string p = "bird"~number.to!(string); 252 if (p~"-x" in s) 253 x = s[p~"-x"].to!(float); 254 else 255 x = def_x; 256 257 if (p~"-y" in s) 258 y = s[p~"-y"].to!(float); 259 else 260 y = def_y; 261 262 if (p~"-z" in s) 263 z = s[p~"-z"].to!(float); 264 else 265 z = def_z; 266 267 if (p~"-dx" in s) 268 dx = s[p~"-dx"].to!(float); 269 else 270 dx = SPEED; 271 272 if (p~"-dy" in s) 273 dy = s[p~"-dy"].to!(float); 274 else 275 dy = 0.0; 276 277 if (p~"-fly" in s) 278 fly = s[p~"-fly"].to!(int); 279 else 280 fly = 0; 281 282 frame = 0; 283 284 if (p in s) 285 { 286 hidden = (s[p] == "hidden")?1:0; 287 } 288 else 289 { 290 hidden = 0; 291 } 292 } 293 294 override void save(ref string[string] s) 295 { 296 string p = "bird"~number.to!(string); 297 if (hidden == 1) 298 s[p] = "hidden"; 299 if (fly > 0) 300 s[p~"-fly"] = fly.to!(string); 301 302 s[p~"-x"] = x.to!(string); 303 s[p~"-y"] = y.to!(string); 304 s[p~"-z"] = z.to!(string); 305 s[p~"-dx"] = dx.to!(string); 306 s[p~"-dy"] = dy.to!(string); 307 s[p~"-state"] = state.to!(string); 308 } 309 } 310